#include <Kharlia/Core/Common.h>
#include <Kharlia/Core/Logger.h>

#define RES_FUNC(name, attrname) \
    name##Func = LoggerObject.attr(attrname)

#define DEF_FUNC(name) \
    void FLogger::##name##(object msg) const {\
        name##Func(msg);\
    }\
    void FLogger::##name##(str msg) const {\
        name##Func(msg);\
    }\
    void FLogger::##name##(unicode msg) const {\
        name##Func(msg); \
    }\
    void FLogger::##name##(boost::format& fmt) const {\
        name##Func(fmt.str());\
    }

namespace kharlia { namespace core {

FLogger::FLogger(str name) {
    static bool inited = false;

    if (!inited) {
        // Store logger get function to avoid importing, but in our module
        // rather than as a global so we don't have to bother with cleanup
        SetModuleAttr("_getLogger", import("logging").attr("getLogger"));
        inited = true;
    }

    LoggerObject = GetModuleAttr("_getLogger")(name);

    RES_FUNC(Debug, "debug");
    RES_FUNC(Info, "info");
    RES_FUNC(Warning, "warning");
    RES_FUNC(Error, "error");
    RES_FUNC(Critical, "critical");
    RES_FUNC(Exception, "exception");
    RES_FUNC(Log, "log");
}

DEF_FUNC(Debug)
DEF_FUNC(Info)
DEF_FUNC(Warning)
DEF_FUNC(Error)
DEF_FUNC(Critical)
DEF_FUNC(Exception)

void FLogger::Log(ELogLevel level, object msg) const {
    LogFunc(static_cast<int>(level), msg);
}

void FLogger::Log(ELogLevel level, str msg) const {
    LogFunc(static_cast<int>(level), msg);
}

void FLogger::Log(ELogLevel level, unicode msg) const {
    LogFunc(static_cast<int>(level), msg);
}

void FLogger::Log(ELogLevel level, boost::format& fmt) const {
    LogFunc(static_cast<int>(level), fmt.str());
}

shared_ptr<FLogger> FLogger::GetLogger(str name) {
    return shared_ptr<FLogger>(new FLogger(name));
}

shared_ptr<FLogger> FLogger::GetLogger(unicode name) {
    return shared_ptr<FLogger>(new FLogger(str(name)));
}

}} // namespace kharlia::core